package com.photoeditor.demo.util;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
import android.provider.Settings;

import com.common.base.ComponentContext;
import com.common.base.utils.DeviceUtils;
import com.common.base.utils.TimeConstant;
import com.common.commercialize.utils.TaskRunnable;
import com.photoeditor.demo.statistics.StatisticsUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import static com.photoeditor.demo.statistics.StatisticsConstant.STATISTIC_EVENT_CHANGETIME;

/**
 * Created by dell on 2017/11/27.
 */

public class TimeAutoCheckUtils {

    private static String TAG = TimeAutoCheckUtils.class.getSimpleName();

    private static final String NET_GOOGLE_URL = "https://www.google.com";
    private static final String NET_FACEBOOK_URL = "https://www.facebook.com/";
    private static final String NET_WIKI_URL = "https://www.wikipedia.org";

    private static final int NET_TIME_OUT = (int) (30 * TimeConstant.ONE_SEC);
    private static final int NET_DEVIATION_TIME = (int) (TimeConstant.ONE_HOUR);

    private static final int STATE_NO = 0;
    private static final int STATE_CHECKING = 1;
    private static final int STATE_CHECK_NET_FAILED = 2;
    private static final int STATE_DONE = 3;

    private static TimeAutoCheckUtils instance;

    private List<String> netUrls = new ArrayList<>();
    private boolean isTimeAuto = true;
//    private boolean lastIsTimeAuto; // 上一次检查的结果，用于统计
    private int state;

    private long networkRealTime;
    private long systemElapsedRealTime;

    private TimeChangedReceiver timeChangedReceiver;
    private TimeChangedReceiver.TimeChangeListener timeChangeListener = new TimeChangedReceiver.TimeChangeListener() {
        @Override
        public void onTimeChange() {
            checkTime();
        }
    };
//    private NetWorkStateReceiver netWorkStateReceiver;
//    private NetWorkStateReceiver.NetWorkStateListener netWorkStateListener = new NetWorkStateReceiver.NetWorkStateListener() {
//        @Override
//        public void onNetWorkStateChange() {
//            if (state == STATE_CHECK_NET_FAILED) {
//                checkTime();
//            }
//        }
//    };

    private TimeAutoCheckUtils() {
        netUrls.add(NET_GOOGLE_URL);
        netUrls.add(NET_FACEBOOK_URL);
        netUrls.add(NET_WIKI_URL);
    }

    public static TimeAutoCheckUtils getInstance() {
        if (instance == null) {
            instance = new TimeAutoCheckUtils();
        }
        return instance;
    }

    public void setUp() {
        state = STATE_NO;

        networkRealTime = 0;
        systemElapsedRealTime = 0;

        timeChangedReceiver = new TimeChangedReceiver();
        timeChangedReceiver.setListener(timeChangeListener);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_TIME_CHANGED);
        intentFilter.addAction(Intent.ACTION_DATE_CHANGED);
        ComponentContext.getContext().registerReceiver(timeChangedReceiver, intentFilter);

//        netWorkStateReceiver = new NetWorkStateReceiver();
//        netWorkStateReceiver.setNetWorkStateListener(netWorkStateListener);
//        IntentFilter intentFilter1 = new IntentFilter();
//        intentFilter1.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
//        ComponentContext.getContext().registerReceiver(netWorkStateReceiver, intentFilter1);

        checkTime();
    }

    public boolean isTimeAuto() {
        if (state == STATE_CHECK_NET_FAILED) {
            checkTime();
        }
        return isTimeAuto;
    }

    private void checkTime() {
//        lastIsTimeAuto = isTimeAuto;
        checkTimeAutoByDB();
        if (!isTimeAuto) {
            checkTimeAutoByNet();
        }
    }

    private boolean checkTimeAutoByDB() {
        int auto = 0;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            auto = Settings.Global.getInt(ComponentContext.getContext().getContentResolver(), Settings.Global.AUTO_TIME, 0);
        } else {
            auto = Settings.System.getInt(ComponentContext.getContext().getContentResolver(), Settings.System.AUTO_TIME, 0);
        }
        if (auto == 1) {
            isTimeAuto = true;
            state = STATE_DONE;
            /**
             * 这里只有网络连接正常时可以当作网络时间
             * 若系统开机时未连网，再打开自动更新，这时候不会更新时间
             */
            if (DeviceUtils.isNetworkAvailable() && (networkRealTime == 0 || systemElapsedRealTime == 0)) {
                // 本地时间未被调整，可当做网络时间
                networkRealTime = System.currentTimeMillis();
                systemElapsedRealTime = SystemClock.elapsedRealtime();
            }
        } else {
            isTimeAuto = false;
        }
        return isTimeAuto;
    }

    private void checkTimeAutoByNet() {
        if (state == STATE_CHECKING) {
            return;
        }
        if (networkRealTime != 0 && systemElapsedRealTime != 0) {
            long currentClockTime = SystemClock.elapsedRealtime();
            long currentTime = System.currentTimeMillis();

            if (Math.abs(networkRealTime - systemElapsedRealTime - currentTime + currentClockTime) < NET_DEVIATION_TIME) {
                isTimeAuto = true;
            } else {
                statisticChangeTime();
                isTimeAuto = false;
            }
            return;
        }
        state = STATE_CHECKING;

        TaskRunnable taskRunnable = new TaskRunnable(TaskRunnable.TYPE_BACKGROUND) {
            final int NET_INVALID = -10000;
            @Override
            public void run() {
                long netTime = NET_INVALID;

                try {
                    Class cls = Class.forName("android.util.NtpTrustedTime");
                    Method forceRefresh = cls.getMethod("forceRefresh", new Class[0]);
                    Object instance = cls.getMethod("getInstance", new Class[]{Context.class})
                            .invoke(cls, new Object[]{ComponentContext.getContext()});
                    boolean isSuccess = ((Boolean) forceRefresh.invoke(instance, new Object[0])).booleanValue();
                    if (isSuccess) {
                        netTime = ((Long) cls.getMethod("getCachedNtpTime", new Class[0]).invoke(instance, new Object[0])).longValue();
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (Throwable e) {
                    //nothing
                }

                if (netTime <= 0) {
                    if (!DeviceUtils.isNetworkAvailable()) {
                    } else {
                        for (String netUrl : netUrls) {
                            URL url = null;//取得资源对象
                            try {
                                url = new URL(netUrl);
                                URLConnection uc = url.openConnection();//生成连接对象
                                uc.setConnectTimeout(NET_TIME_OUT);
                                uc.connect(); //发出连接
                                netTime = uc.getDate(); //取得网站日期时间
                                if (netTime == 0) {
                                    continue;
                                }
                                systemElapsedRealTime = SystemClock.elapsedRealtime();
                                break;
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }

                if (netTime <= 0) {
                    if (netTime == 0) {
                    }
                    state = STATE_CHECK_NET_FAILED;
                    systemElapsedRealTime = 0;
                    isTimeAuto = true;
                    return;
                }
                long localTime = System.currentTimeMillis();

                networkRealTime = netTime;

                if (Math.abs(netTime - localTime) < NET_DEVIATION_TIME) {
                    isTimeAuto = true;
                } else {
                    statisticChangeTime();
                    isTimeAuto = false;
                }
                state = STATE_DONE;
            }
        };
        taskRunnable.runSelfAdaptation();
    }

    private void statisticChangeTime() {
        StatisticsUtils.statisticsCustomFunction(STATISTIC_EVENT_CHANGETIME);
    }
}
